package hight;

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.StampedLock;

/**
 * writeLock与unlockWrite必须成对使用，解锁是必须要传入相应的dstmp才可以释放锁，每次获得锁之后都会得到一个新的stamp值
 * 同一个线程获取锁后，再次尝试获取锁而无法获取，是非重入锁
 * 对于ReentrantLock,是重入锁
 * 对于ReentrantReadWriteLock.ReadLock也为重入锁
 * StampedLock.writeLock是排他锁
 */
public class StampedLockTest {
    // 与 ReentrantReadWirteLock 功能类似提供三种读写锁
    // StampedLock中映入了一个stamp(邮戳)的概念，他代表线程取到锁的版本，每一把锁都有唯一的stamp
    // 写锁wirteLock 时排他锁，也叫独占锁，相同时间只能有一个线程获取锁，其他线程请求读锁和写锁都会被阻塞
    // 功能类似与ReentrantReadWriteLick.wirteLock
    // 区别时StampedLock的写锁时不可重入锁，当前没有线程持有读锁和写锁的时候才可以获得获取到该锁
    // 读读共享，写写互斥，读写互斥
    public static void main(String[] args) {
        StampedLock s1 = new StampedLock();
        // 获取读锁，并且返回stamp
        long stamp = s1.writeLock();
        System.out.println("获取写锁 stamp = " + stamp);
        // 使用完毕，释放锁
        s1.unlockWrite(stamp);
        // 再次获取读锁，并且返回stamp
        stamp = s1.writeLock();
        System.out.println("获取写锁 stamp = " + stamp);
        // 使用完毕，释放锁
        s1.unlockWrite(stamp);
        /*** 重入锁对比 **/
//        ReentrantLock r1 = new ReentrantLock();
//        r1.lock();
//        System.out.println("获取了锁1 = ");
//        r1.lock();
//        System.out.println("获取了锁2 = ");
//        r1.unlock();
        StampedLock s11 = new StampedLock();
        long stamp1 = s11.tryWriteLock();
        System.out.println("尝试获取锁 = " + stamp1);
        // tryWriteLock 可反复调用
        long stamp2 = s11.tryWriteLock();
        System.out.println("尝试获取锁 = " + stamp2);
        // 不可重入锁，已经获取锁后，调用writeLock 会阻塞
        long stamp3 = s11.writeLock();
        System.out.println("尝试获取锁 = " + stamp3);
        s11.unlockWrite(stamp1);
    }
}
